<?php

/*//. Library Bob - Config File
  ../ In an attempt to standardize my user config file and quit rewriting pretty
  ../ much the same function over and over, this class was built to manage
  ../ loading, reading, parsing, using, setting, and saving of config files.

	class bobConfigFile {

		private string filename;
		private array configdata;	
	
		void method __construct(string filename);
		//. create a new config object from the given config file.
		
		void method save();
		//. save the current config object to the config file.

		string method getFilename(void);
		void method setFilename(string filename);
		//. get and set the current config object filename.

		mixed method get(string configkey);
		void method set(string key, mixed data);
		//. get and set basic config file directives. get() can return a
		//. single directive (string) or an entire group (object).
		
		void method setInGroup(string group, string key, mixed data);
		//. set directive inside a group. if the group does not exist it is
		//. created.

		array method getGroups(void);
		//. return an array of all the config groupings in this file. useful
		//. if the group names are dynamic and need to be evaulated for the
		//. type of data it holds.
		
		string static method mkFilePath(string application, string extension default null);
		//. given the name of an application, generate a config file name that
		//. is useful and filesystem safe. use it to generate a filepath to
		//. pass to the constructor.
		
		array static method parse(string filename);
		void static method write(string filename, array configdata);
		//. perform the actual reading and writing of the config file. these
		//. should not really be used as they are for the constructor.
	}  
  
.//*/

if(!class_exists('bobFile')) {
	require('libbob/file-common.so.php');
}

class bobConfigFile {
	
	private $filename;
	private $data;	
	
	public function __construct($file) {
		$this->filename = $file;
		touch($file);
		$this->data = self::parse($file);		
		return;
	}
	
	public function getFilename() {
		return $this->filename;
	}
	
	public function setFilename($file) {
		$this->filename = $file;
		return;
	}
	
	public function get($value) {
		if(array_key_exists($value,$this->data)) {
			return $this->data[$value];
		} else {
			return null;
		}
	}
	
	public function getAll() {
		return $this->data;
	}

	public function getGroup($key) {
		if(array_key_exists($key,$this->data) && is_object($this->data[$key])) {
			return clone($this->data[$key]);
		} else {
			return null;
		}
	}
	
	public function getGroups() {
		$output = array();
		foreach($this->data as $key => $data) {
			if(is_object($data)) {
				$output[$key] = $data;
			}
		} return $output;
	}
	
	public function setDefault($option,$force = false) {
		foreach($option as $key => $value) {
			if($force || $this->get($key) === null) {
				$this->set($key,$value);
			}
		} return;
	}
	
	public function set($key,$value) {
		if(is_object($value)) {
			foreach($value as $id => $data) {
				$this->setInGroup($key,$id,$data);
			}
		} else {
			$this->data[$key] = $value;
		}
		return;
	}
	
	public function delete($key) {
		if(array_key_exists($key,$this->data)) {
			unset($this->data[$key]);
		} return;
	}
	
	public function setInGroup($group,$key,$value) {
		if(!array_key_exists($group,$this->data) || !is_object($this->data[$group])) {
			$this->data[$group] = new StdClass;
		}
		
		$this->data[$group]->{$key} = $value;
		
		return;
	}
	
	public function save() {
		if(is_writable($this->filename)) {
			self::write($this->filename,$this->data);
		}
		return;
	}

	static function mkFilePath($app,$global = false) {
		if($global) {
			if(BOB_UNIX) {
				$path = sprintf(
					'%s/%s/config.conf',
					$global,
					bobFile::safeFilename($app)		
				);
			} else {
				$path = sprintf(
					'%s/%s/config.conf',
					$global,
					bobFile::safeFilename($app)		
				);
			}
		} else {
			if(BOB_UNIX) {
				$path = sprintf(
					'%s/.%s/config.conf',
					BOB_HOME,
					bobFile::safeFilename($app)		
				);
			} else {
				$path = sprintf(
					'%s/%s/config.conf',
					BOB_HOME,
					bobFile::safeFilename($app)		
				);
			}		
		}
		
		bobFile::mkdir(dirname($path));
		touch($path);
		return $path;
	}
	
	static function parse($file) {
		$output = array();

		$ingroup = false;
		$group = null;
		$groupname = null;

		if(!file_exists($file)) {
			fwrite(STDERR,"ERROR: {$file} not found, creating empty file.\n");
			bobFile::mkdir(dirname($file));
			touch($file);
		} else {	
			$fp = fopen($file,'r');
			while(!feof($fp)) {
				$line = rtrim(fgets($fp));
				
				if(!$ingroup && preg_match('/(.+) \{$/',$line,$match)) {
					$group = new StdClass;
					$groupname = $match[1];
					$ingroup = true;
				}
				
				else if($ingroup && preg_match('/^\}/',$line)) {
					$ingroup = false;
					$output[$groupname] = $group;
					unset($group,$groupname);
				}
				
				else if($ingroup && preg_match("/^\t([a-zA-Z0-9_]+) \"(.+?)\"/",$line,$match)) {
					$group->{$match[1]} = $match[2];
				}
				
				else if(!$ingroup && preg_match("/^([a-zA-Z0-9_-]+) \"(.+?)\"/",$line,$match)) {
					$output[$match[1]] = $match[2];
				}
				
			} fclose($fp);
		}
		
		return $output;
	}
	
	static function write($file,$input) {
	
		$fp = fopen($file,'w');
		foreach($input as $key => $data) {
			if(is_object($data)) {
				fwrite($fp,"{$key} {\n");
				foreach($data as $property => $value) {
					if(is_array($value)) { $value = join(',',$value); }
					fwrite($fp,"\t{$property} \"{$value}\"\n");
				}
				fwrite($fp,"}\n");
			} else {
				if(is_array($data)) { $data = join(',',$data); }
				fwrite($fp,"{$key} \"{$data}\"\n");
			}
		} fclose($fp);
	
		return;
	}
}

?>